home *** CD-ROM | disk | FTP | other *** search
/ Ultra Pack / UltraComputing Partner Applications.iso / SunLabs / tclTK / src / tk4.0 / tkClipboard.c < prev    next >
C/C++ Source or Header  |  1995-05-11  |  19KB  |  631 lines

  1. /*
  2.  * tkClipboard.c --
  3.  *
  4.  *     This file manages the clipboard for the Tk toolkit,
  5.  *     maintaining a collection of data buffers that will be
  6.  *     supplied on demand to requesting applications.
  7.  *
  8.  * Copyright (c) 1994 The Regents of the University of California.
  9.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  */
  14.  
  15. static char sccsid[] = "@(#) tkClipboard.c 1.10 95/05/11 09:37:17";
  16.  
  17. #include "tkInt.h"
  18. #include "tkPort.h"
  19.  
  20. /*
  21.  * The clipboard contains a list of buffers of various types and formats.
  22.  * All of the buffers of a given type will be returned in sequence when the
  23.  * CLIPBOARD selection is retrieved.  All buffers of a given type on the
  24.  * same clipboard must have the same format.  The TkClipboardTarget structure
  25.  * is used to record the information about a chain of buffers of the same
  26.  * type.
  27.  */
  28.  
  29. typedef struct ClipboardBuffer {
  30.     char *buffer;            /* Null terminated data buffer. */
  31.     long length;            /* Length of string in buffer. */
  32.     struct ClipboardBuffer *nextPtr;    /* Next in list of buffers.  NULL
  33.                      * means end of list . */
  34. } ClipboardBuffer;
  35.  
  36. typedef struct TkClipboardTarget {
  37.     Atom type;                /* Type conversion supported. */
  38.     Atom format;            /* Representation used for data. */
  39.     ClipboardBuffer *firstBufferPtr;    /* First in list of data buffers. */
  40.     ClipboardBuffer *lastBufferPtr;    /* Last in list of clipboard buffers.
  41.                      * Used to speed up appends. */
  42.     struct TkClipboardTarget *nextPtr;    /* Next in list of targets on
  43.                      * clipboard.  NULL means end of
  44.                      * list. */
  45. } TkClipboardTarget;
  46.  
  47. /*
  48.  * Prototypes for procedures used only in this file:
  49.  */
  50.  
  51. static int        ClipboardAppHandler _ANSI_ARGS_((ClientData clientData,
  52.                 int offset, char *buffer, int maxBytes));
  53. static int        ClipboardHandler _ANSI_ARGS_((ClientData clientData,
  54.                 int offset, char *buffer, int maxBytes));
  55. static int        ClipboardWindowHandler _ANSI_ARGS_((
  56.                 ClientData clientData, int offset, char *buffer,
  57.                 int maxBytes));
  58. static void        ClipboardLostSel _ANSI_ARGS_((ClientData clientData));
  59.  
  60. /*
  61.  *----------------------------------------------------------------------
  62.  *
  63.  * ClipboardHandler --
  64.  *
  65.  *    This procedure acts as selection handler for the
  66.  *    clipboard manager.  It extracts the required chunk of
  67.  *    data from the buffer chain for a given selection target.
  68.  *
  69.  * Results:
  70.  *    The return value is a count of the number of bytes
  71.  *    actually stored at buffer.
  72.  *
  73.  * Side effects:
  74.  *    None.
  75.  *
  76.  *----------------------------------------------------------------------
  77.  */
  78.  
  79. static int
  80. ClipboardHandler(clientData, offset, buffer, maxBytes)
  81.     ClientData clientData;    /* Information about data to fetch. */
  82.     int offset;            /* Return selection bytes starting at this
  83.                  * offset. */
  84.     char *buffer;        /* Place to store converted selection. */
  85.     int maxBytes;        /* Maximum # of bytes to store at buffer. */
  86. {
  87.     TkClipboardTarget *targetPtr = (TkClipboardTarget*) clientData;
  88.     ClipboardBuffer *cbPtr;
  89.     char *srcPtr, *destPtr;
  90.     int count = 0;
  91.     int scanned = 0;
  92.     size_t length, freeCount;
  93.  
  94.     /*
  95.      * Skip to buffer containing offset byte
  96.      */
  97.  
  98.     for (cbPtr = targetPtr->firstBufferPtr; ; cbPtr = cbPtr->nextPtr) {
  99.     if (cbPtr == NULL) {
  100.         return 0;
  101.     }
  102.     if (scanned + cbPtr->length > offset) {
  103.         break;
  104.     }
  105.     scanned += cbPtr->length;
  106.     }
  107.  
  108.     /*
  109.      * Copy up to maxBytes or end of list, switching buffers as needed.
  110.      */
  111.  
  112.     freeCount = maxBytes;
  113.     srcPtr = cbPtr->buffer + (offset - scanned);
  114.     destPtr = buffer;
  115.     length = cbPtr->length - (offset - scanned);
  116.     while (1) {
  117.     if (length > freeCount) {
  118.         strncpy(destPtr, srcPtr, freeCount);
  119.         return maxBytes;
  120.     } else {
  121.         strncpy(destPtr, srcPtr, length);
  122.         destPtr += length;
  123.         count += length;
  124.         freeCount -= length;
  125.     }
  126.     cbPtr = cbPtr->nextPtr;
  127.     if (cbPtr == NULL) {
  128.         break;
  129.     }
  130.     srcPtr = cbPtr->buffer;
  131.     length = cbPtr->length;
  132.     }
  133.     return count;
  134. }
  135.  
  136. /*
  137.  *----------------------------------------------------------------------
  138.  *
  139.  * ClipboardAppHandler --
  140.  *
  141.  *    This procedure acts as selection handler for retrievals of type
  142.  *    TK_APPLICATION.  It returns the name of the application that
  143.  *    owns the clipboard.  Note:  we can't use the default Tk
  144.  *    selection handler for this selection type, because the clipboard
  145.  *    window isn't a "real" window and doesn't have the necessary
  146.  *    information.
  147.  *
  148.  * Results:
  149.  *    The return value is a count of the number of bytes
  150.  *    actually stored at buffer.
  151.  *
  152.  * Side effects:
  153.  *    None.
  154.  *
  155.  *----------------------------------------------------------------------
  156.  */
  157.  
  158. static int
  159. ClipboardAppHandler(clientData, offset, buffer, maxBytes)
  160.     ClientData clientData;    /* Pointer to TkDisplay structure. */
  161.     int offset;            /* Return selection bytes starting at this
  162.                  * offset. */
  163.     char *buffer;        /* Place to store converted selection. */
  164.     int maxBytes;        /* Maximum # of bytes to store at buffer. */
  165. {
  166.     TkDisplay *dispPtr = (TkDisplay *) clientData;
  167.     size_t length;
  168.     char *p;
  169.  
  170.     p = dispPtr->clipboardAppPtr->winPtr->nameUid;
  171.     length = strlen(p);
  172.     length -= offset;
  173.     if (length <= 0) {
  174.     return 0;
  175.     }
  176.     if (length > maxBytes) {
  177.     length = maxBytes;
  178.     }
  179.     strncpy(buffer, p, length);
  180.     return length;
  181. }
  182.  
  183. /*
  184.  *----------------------------------------------------------------------
  185.  *
  186.  * ClipboardWindowHandler --
  187.  *
  188.  *    This procedure acts as selection handler for retrievals of
  189.  *    type TK_WINDOW.  Since the clipboard doesn't correspond to
  190.  *    any particular window, we just return ".".  We can't use Tk's
  191.  *    default handler for this selection type, because the clipboard
  192.  *    window isn't a valid window.
  193.  *
  194.  * Results:
  195.  *    The return value is 1, the number of non-null bytes stored
  196.  *    at buffer.
  197.  *
  198.  * Side effects:
  199.  *    None.
  200.  *
  201.  *----------------------------------------------------------------------
  202.  */
  203.  
  204. static int
  205. ClipboardWindowHandler(clientData, offset, buffer, maxBytes)
  206.     ClientData clientData;    /* Not used. */
  207.     int offset;            /* Return selection bytes starting at this
  208.                  * offset. */
  209.     char *buffer;        /* Place to store converted selection. */
  210.     int maxBytes;        /* Maximum # of bytes to store at buffer. */
  211. {
  212.     buffer[0] = '.';
  213.     buffer[1] = 0;
  214.     return 1;
  215. }
  216.  
  217. /*
  218.  *----------------------------------------------------------------------
  219.  *
  220.  * ClipboardLostSel --
  221.  *
  222.  *    This procedure is invoked whenever clipboard ownership is
  223.  *    claimed by another window.  It just sets a flag so that we
  224.  *    know the clipboard was taken away.
  225.  *
  226.  * Results:
  227.  *    None.
  228.  *
  229.  * Side effects:
  230.  *    The clipboard is marked as inactive.
  231.  *
  232.  *----------------------------------------------------------------------
  233.  */
  234.  
  235. static void
  236. ClipboardLostSel(clientData)
  237.     ClientData clientData;        /* Pointer to TkDisplay structure. */
  238. {
  239.     TkDisplay *dispPtr = (TkDisplay*) clientData;
  240.  
  241.     dispPtr->clipboardActive = 0;
  242. }
  243.  
  244. /*
  245.  *----------------------------------------------------------------------
  246.  *
  247.  * Tk_ClipboardClear --
  248.  *
  249.  *    Take control of the clipboard and clear out the previous
  250.  *    contents.  This procedure must be invoked before any
  251.  *    calls to Tk_AppendToClipboard.
  252.  *
  253.  * Results:
  254.  *    A standard Tcl result.  If an error occurs, an error message is
  255.  *    left in interp->result.
  256.  *
  257.  * Side effects:
  258.  *    From now on, requests for the CLIPBOARD selection will be
  259.  *    directed to the clipboard manager routines associated with
  260.  *    clipWindow for the display of tkwin.  In order to guarantee
  261.  *    atomicity, no event handling should occur between
  262.  *    Tk_ClipboardClear and the following Tk_AppendToClipboard
  263.  *    calls.  This procedure may cause a user-defined LostSel command 
  264.  *     to be invoked when the CLIPBOARD is claimed, so any calling
  265.  *    function should be reentrant at the point Tk_ClipboardClear is
  266.  *    invoked.
  267.  *
  268.  *----------------------------------------------------------------------
  269.  */
  270.  
  271. int
  272. Tk_ClipboardClear(interp, tkwin)
  273.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  274.     Tk_Window tkwin;        /* Window in application that is clearing
  275.                  * clipboard;  identifies application and
  276.                  * display. */
  277. {
  278.     TkWindow *winPtr = (TkWindow *) tkwin;
  279.     TkDisplay *dispPtr = winPtr->dispPtr;
  280.     TkClipboardTarget *targetPtr, *nextTargetPtr;
  281.     ClipboardBuffer *cbPtr, *nextCbPtr;
  282.  
  283.     if (dispPtr->clipWindow == NULL) {
  284.     int result;
  285.  
  286.     result = TkClipInit(interp, dispPtr);
  287.     if (result != TCL_OK) {
  288.         return result;
  289.     }
  290.     }
  291.  
  292.     /*
  293.      * Discard any existing clipboard data and delete the selection
  294.      * handler(s) associated with that data.
  295.      */
  296.  
  297.     for (targetPtr = dispPtr->clipTargetPtr; targetPtr != NULL;
  298.         targetPtr = nextTargetPtr) {
  299.     for (cbPtr = targetPtr->firstBufferPtr; cbPtr != NULL;
  300.         cbPtr = nextCbPtr) {
  301.         ckfree(cbPtr->buffer);
  302.         nextCbPtr = cbPtr->nextPtr;
  303.         ckfree((char *) cbPtr);
  304.     }
  305.     nextTargetPtr = targetPtr->nextPtr;
  306.     Tk_DeleteSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom,
  307.         targetPtr->type);
  308.     ckfree((char *) targetPtr);
  309.     }
  310.     dispPtr->clipTargetPtr = NULL;
  311.  
  312.     /*
  313.      * Reclaim the clipboard selection if we lost it.
  314.      */
  315.  
  316.     if (!dispPtr->clipboardActive) {
  317.     Tk_OwnSelection(dispPtr->clipWindow, dispPtr->clipboardAtom,
  318.         ClipboardLostSel, (ClientData) dispPtr);
  319.     dispPtr->clipboardActive = 1;
  320.     }
  321.     dispPtr->clipboardAppPtr = winPtr->mainPtr;
  322.     return TCL_OK;
  323. }
  324.  
  325. /*
  326.  *----------------------------------------------------------------------
  327.  *
  328.  * Tk_ClipboardAppend --
  329.  *
  330.  *     Append a buffer of data to the clipboard.  The first buffer of
  331.  *    a given type determines the format for that type.  Any successive
  332.  *    appends to that type must have the same format or an error will
  333.  *    be returned.  Tk_ClipboardClear must be called before a sequence
  334.  *    of Tk_ClipboardAppend calls can be issued.  In order to guarantee
  335.  *    atomicity, no event handling should occur between Tk_ClipboardClear
  336.  *    and the following Tk_AppendToClipboard calls.
  337.  *
  338.  * Results:
  339.  *    A standard Tcl result.  If an error is returned, an error message
  340.  *    is left in interp->result.
  341.  *
  342.  * Side effects:
  343.  *     The specified buffer will be copied onto the end of the clipboard.
  344.  *    The clipboard maintains a list of buffers which will be used to
  345.  *    supply the data for a selection get request.  The first time a given
  346.  *    type is appended, Tk_ClipboardAppend will register a selection
  347.  *     handler of the appropriate type.
  348.  *
  349.  *----------------------------------------------------------------------
  350.  */
  351.  
  352. int
  353. Tk_ClipboardAppend(interp, tkwin, type, format, buffer)
  354.     Tcl_Interp *interp;        /* Used for error reporting. */
  355.     Tk_Window tkwin;        /* Window that selects a display. */
  356.     Atom type;            /* The desired conversion type for this
  357.                  * clipboard item, e.g. STRING or LENGTH. */
  358.     Atom format;        /* Format in which the selection
  359.                  * information should be returned to
  360.                  * the requestor. */
  361.     char* buffer;        /* NULL terminated string containing the data
  362.                  * to be added to the clipboard. */
  363. {
  364.     TkWindow *winPtr = (TkWindow *) tkwin;
  365.     TkDisplay *dispPtr = winPtr->dispPtr;
  366.     TkClipboardTarget *targetPtr;
  367.     ClipboardBuffer *cbPtr;
  368.  
  369.     /*
  370.      * If this application doesn't already own the clipboard, clear
  371.      * the clipboard.  If we don't own the clipboard selection, claim it.
  372.      */
  373.  
  374.     if (dispPtr->clipboardAppPtr != winPtr->mainPtr) {
  375.     Tk_ClipboardClear(interp, tkwin);
  376.     } else if (!dispPtr->clipboardActive) {
  377.     Tk_OwnSelection(dispPtr->clipWindow, dispPtr->clipboardAtom,
  378.         ClipboardLostSel, (ClientData) dispPtr);
  379.     dispPtr->clipboardActive = 1;
  380.     }
  381.  
  382.     /*
  383.      * Check to see if the specified target is already present on the
  384.      * clipboard.  If it isn't, we need to create a new target; otherwise,
  385.      * we just append the new buffer to the clipboard list.
  386.      */
  387.  
  388.     for (targetPtr = dispPtr->clipTargetPtr; targetPtr != NULL;
  389.         targetPtr = targetPtr->nextPtr) {
  390.     if (targetPtr->type == type)
  391.         break;
  392.     }
  393.     if (targetPtr == NULL) {
  394.     targetPtr = (TkClipboardTarget*) ckalloc(sizeof(TkClipboardTarget));
  395.     targetPtr->type = type;
  396.     targetPtr->format = format;
  397.     targetPtr->firstBufferPtr = targetPtr->lastBufferPtr = NULL;
  398.     targetPtr->nextPtr = dispPtr->clipTargetPtr;
  399.     dispPtr->clipTargetPtr = targetPtr;
  400.     Tk_CreateSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom,
  401.         type, ClipboardHandler, (ClientData) targetPtr, format);
  402.     } else if (targetPtr->format != format) {
  403.     Tcl_AppendResult(interp, "format \"", Tk_GetAtomName(tkwin, format),
  404.         "\" does not match current format \"",
  405.         Tk_GetAtomName(tkwin, targetPtr->format),"\" for ",
  406.         Tk_GetAtomName(tkwin, type), (char *) NULL);
  407.     return TCL_ERROR;
  408.     }
  409.  
  410.     /*
  411.      * Append a new buffer to the buffer chain.
  412.      */
  413.  
  414.     cbPtr = (ClipboardBuffer*) ckalloc(sizeof(ClipboardBuffer));
  415.     cbPtr->nextPtr = NULL;
  416.     if (targetPtr->lastBufferPtr != NULL) {
  417.     targetPtr->lastBufferPtr->nextPtr = cbPtr;
  418.     } else {
  419.     targetPtr->firstBufferPtr = cbPtr;
  420.     }
  421.     targetPtr->lastBufferPtr = cbPtr;
  422.  
  423.     cbPtr->length = strlen(buffer);
  424.     cbPtr->buffer = (char *) ckalloc((unsigned) (cbPtr->length + 1));
  425.     strcpy(cbPtr->buffer, buffer);
  426.  
  427.     return TCL_OK;
  428. }
  429.  
  430. /*
  431.  *----------------------------------------------------------------------
  432.  *
  433.  * Tk_ClipboardCmd --
  434.  *
  435.  *    This procedure is invoked to process the "clipboard" Tcl
  436.  *    command.  See the user documentation for details on what
  437.  *    it does.
  438.  *
  439.  * Results:
  440.  *    A standard Tcl result.
  441.  *
  442.  * Side effects:
  443.  *    See the user documentation.
  444.  *
  445.  *----------------------------------------------------------------------
  446.  */
  447.  
  448. int
  449. Tk_ClipboardCmd(clientData, interp, argc, argv)
  450.     ClientData clientData;    /* Main window associated with
  451.                  * interpreter. */
  452.     Tcl_Interp *interp;        /* Current interpreter. */
  453.     int argc;            /* Number of arguments. */
  454.     char **argv;        /* Argument strings. */
  455. {
  456.     Tk_Window tkwin = (Tk_Window) clientData;
  457.     char *path = NULL;
  458.     size_t length;
  459.     int count;
  460.     char c;
  461.     char **args;
  462.  
  463.     if (argc < 2) {
  464.     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
  465.         " option ?arg arg ...?\"", (char *) NULL);
  466.     return TCL_ERROR;
  467.     }
  468.     c = argv[1][0];
  469.     length = strlen(argv[1]);
  470.     if ((c == 'a') && (strncmp(argv[1], "append", length) == 0)) {
  471.     Atom target, format;
  472.     char *targetName = NULL;
  473.     char *formatName = NULL;
  474.  
  475.     for (count = argc-2, args = argv+2; count > 1; count -= 2, args += 2) {
  476.         if (args[0][0] != '-') {
  477.         break;
  478.         }
  479.         c = args[0][1];
  480.         length = strlen(args[0]);
  481.         if ((c == '-') && (length == 2)) {
  482.         args++;
  483.         count--;
  484.         break;
  485.         }
  486.         if ((c == 'd') && (strncmp(args[0], "-displayof", length) == 0)) {
  487.         path = args[1];
  488.         } else if ((c == 'f')
  489.             && (strncmp(args[0], "-format", length) == 0)) {
  490.         formatName = args[1];
  491.         } else if ((c == 't')
  492.             && (strncmp(args[0], "-type", length) == 0)) {
  493.         targetName = args[1];
  494.         } else {
  495.         Tcl_AppendResult(interp, "unknown option \"", args[0],
  496.             "\"", (char *) NULL);
  497.         return TCL_ERROR;
  498.         }
  499.     }
  500.     if (count != 1) {
  501.         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
  502.             " append ?options? data\"", (char *) NULL);
  503.         return TCL_ERROR;
  504.     }
  505.     if (path != NULL) {
  506.         tkwin = Tk_NameToWindow(interp, path, tkwin);
  507.     }
  508.     if (tkwin == NULL) {
  509.         return TCL_ERROR;
  510.     }
  511.     if (targetName != NULL) {
  512.         target = Tk_InternAtom(tkwin, targetName);
  513.     } else {
  514.         target = XA_STRING;
  515.     }
  516.     if (formatName != NULL) {
  517.         format = Tk_InternAtom(tkwin, formatName);
  518.     } else {
  519.         format = XA_STRING;
  520.     }
  521.     return Tk_ClipboardAppend(interp, tkwin, target, format, args[0]);
  522.     } else if ((c == 'c') && (strncmp(argv[1], "clear", length) == 0)) {
  523.     for (count = argc-2, args = argv+2; count > 0; count -= 2, args += 2) {
  524.         if (args[0][0] != '-') {
  525.         break;
  526.         }
  527.         if (count < 2) {
  528.         Tcl_AppendResult(interp, "value for \"", *args,
  529.             "\" missing", (char *) NULL);
  530.         return TCL_ERROR;
  531.         }
  532.         c = args[0][1];
  533.         length = strlen(args[0]);
  534.         if ((c == 'd') && (strncmp(args[0], "-displayof", length) == 0)) {
  535.         path = args[1];
  536.         } else {
  537.         Tcl_AppendResult(interp, "unknown option \"", args[0],
  538.             "\"", (char *) NULL);
  539.         return TCL_ERROR;
  540.         }
  541.     }
  542.     if (count > 0) {
  543.         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
  544.             " clear ?options?\"", (char *) NULL);
  545.         return TCL_ERROR;
  546.     }
  547.     if (path != NULL) {
  548.         tkwin = Tk_NameToWindow(interp, path, tkwin);
  549.     }
  550.     if (tkwin == NULL) {
  551.         return TCL_ERROR;
  552.     }
  553.     return Tk_ClipboardClear(interp, tkwin);
  554.     } else {
  555.     sprintf(interp->result,
  556.         "bad option \"%.50s\":  must be clear or append",
  557.         argv[1]);
  558.     return TCL_ERROR;
  559.     }
  560. }
  561.  
  562. /*
  563.  *----------------------------------------------------------------------
  564.  *
  565.  * TkClipInit --
  566.  *
  567.  *    This procedure is called to initialize the window for claiming
  568.  *    clipboard ownership and for receiving selection get results.  This
  569.  *    function is called from tkSelect.c as well as tkClipboard.c.
  570.  *
  571.  * Results:
  572.  *    The result is a standard Tcl return value, which is normally TCL_OK.
  573.  *    If an error occurs then an error message is left in interp->result
  574.  *    and TCL_ERROR is returned.
  575.  *
  576.  * Side effects:
  577.  *    Sets up the clipWindow and related data structures.
  578.  *
  579.  *----------------------------------------------------------------------
  580.  */
  581.  
  582. int
  583. TkClipInit(interp, dispPtr)
  584.     Tcl_Interp *interp;        /* Interpreter to use for error
  585.                  * reporting. */
  586.     register TkDisplay *dispPtr;/* Display to initialize. */
  587. {
  588.     XSetWindowAttributes atts;
  589.  
  590.     dispPtr->clipTargetPtr = NULL;
  591.     dispPtr->clipboardActive = 0;
  592.     dispPtr->clipboardAppPtr = NULL;
  593.     
  594.     /*
  595.      * Create the window used for clipboard ownership and selection retrieval,
  596.      * and set up an event handler for it.
  597.      */
  598.  
  599.     dispPtr->clipWindow = Tk_CreateWindow(interp, (Tk_Window) NULL,
  600.         "_clip", DisplayString(dispPtr->display));
  601.     if (dispPtr->clipWindow == NULL) {
  602.     return TCL_ERROR;
  603.     }
  604.     atts.override_redirect = True;
  605.     Tk_ChangeWindowAttributes(dispPtr->clipWindow, CWOverrideRedirect, &atts);
  606.     Tk_MakeWindowExist(dispPtr->clipWindow);
  607.  
  608.     if (dispPtr->multipleAtom == None) {
  609.     /*
  610.      * Need to invoke selection initialization to make sure that
  611.      * atoms we depend on below are defined.
  612.      */
  613.  
  614.     TkSelInit(dispPtr->clipWindow);
  615.     }
  616.  
  617.     /*
  618.      * Create selection handlers for types TK_APPLICATION and TK_WINDOW
  619.      * on this window.  Can't use the default handlers for these types
  620.      * because this isn't a full-fledged window.
  621.      */
  622.  
  623.     Tk_CreateSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom,
  624.         dispPtr->applicationAtom, ClipboardAppHandler,
  625.         (ClientData) dispPtr, XA_STRING);
  626.     Tk_CreateSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom,
  627.         dispPtr->windowAtom, ClipboardWindowHandler,
  628.         (ClientData) dispPtr, XA_STRING);
  629.     return TCL_OK;
  630. }
  631.